﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SweeperLibrary.Properties;
using Timer = System.Threading.Timer;

namespace SweeperLibrary
{
    public delegate void OnGameOverDelegate();

    public delegate void OnShowANumberDelegate();

    public delegate void OnPublishGameTimeDelegate(string timeDescription);

    public partial class GameView : UserControl
    {

        /// <summary>
        /// 游戏结束事件
        /// </summary>
        public event OnGameOverDelegate OnGameOverEvent;

        /// <summary>
        /// 当一个格子被点击时，显示当前数字的事件
        /// </summary>
        public event OnShowANumberDelegate OnShowANumberEvent;

        /// <summary>
        /// 发布当前游戏的时间
        /// </summary>
        public event OnPublishGameTimeDelegate OnPublishGameTimeEvent;

        /// <summary>
        /// 游戏绘制地图的每个格子的大小
        /// </summary>
        public static readonly int CellSize = 40;

        /// <summary>
        /// 游戏规模N*N
        /// </summary>
        public static readonly int GameCellCount = 10;

        /// <summary>
        /// 移动方向坐标点改变的数组
        /// </summary>
        public static readonly int[][] MoveDirectionPoints = {
            new[]{-1, -1},
            new[] {0, -1},
            new[] {1, -1},
            new[] {1, 0},
            new[] {1, 1},
            new[] {0, 1},
            new[] {-1, 1},
            new[] {-1, 0}
        };

        /// <summary>
        /// 随机数雷生成对象
        /// </summary>
        private static readonly Random Random = new Random(Guid.NewGuid().GetHashCode());
        /// <summary>
        /// 游戏地图标识数组
        /// </summary>
        private CellBlockRole[][] gameMap = new CellBlockRole[GameCellCount][];

        /// <summary>
        /// 雷的数量，默认为10
        /// </summary>
        public int BoomCount { get; set; } = 20;

        /// <summary>
        /// 红旗数量， 默认数量为10
        /// </summary>
        public int RedFlagCount { get; set; } = 20;

        /// <summary>
        /// 游戏开始时间
        /// </summary>
        private DateTime gameStartTime;

        /// <summary>
        /// 计时定时器
        /// </summary>
        private System.Windows.Forms.Timer gameTimer = new System.Windows.Forms.Timer();

        public GameView()
        {
            InitializeComponent();
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            InitGame(); //默认游戏已经开始
            SetGameTimer(); //设置游戏定时器
        }

        private void GameView_Paint(object sender, PaintEventArgs e)
        {
            Width = GameCellCount + 1 + GameCellCount * CellSize;
            Height = GameCellCount + 1 + GameCellCount * CellSize;
            //绘制游戏界面
            Graphics graphics = e.Graphics;
            graphics.Clear(Color.White);
            if (gameMap != null && gameMap.Length > 0 && gameMap[0] != null && gameMap[0].Length > 0)
            {
                for (int y = 0; y < GameCellCount; y++)
                {
                    for (int x = 0; x < GameCellCount; x++)
                    {
                        int dx = x + 1 + x * CellSize,
                            dy = y + 1 + y * CellSize;
                        CellBlockRole cellBlockRole = gameMap[y][x];
                        graphics.FillRectangle(new SolidBrush(cellBlockRole.IsShowResult ? Color.LightSlateGray : Color.DarkGray),
                            dx, dy, CellSize, CellSize);
                        graphics.DrawRectangle(new Pen(Color.White), dx, dy, CellSize, CellSize);
                        if (cellBlockRole.IsShowResult && cellBlockRole.Number != 0)
                        {
                            switch (cellBlockRole.Number)
                            {
                                case -1: //雷
                                    graphics.DrawImage(Image.FromHbitmap(Resources.boom.GetHbitmap()),
                                        new RectangleF(dx, dy, CellSize, CellSize));
                                    if (cellBlockRole.IsFlag) //如果是已经被标记的雷，显示的时候蒙上一层红色
                                    {
                                        graphics.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 0, 0)),
                                            dx, dy, CellSize, CellSize);
                                    }
                                    break;
                                default: //数字
                                    string drawText = cellBlockRole.Number.ToString();
                                    Font textFont = new Font(FontFamily.GenericSansSerif, 12, FontStyle.Bold);
                                    SizeF textSize = graphics.MeasureString(drawText, textFont);
                                    graphics.DrawString(drawText, textFont, new SolidBrush(Color.White),
                                        dx + (CellSize - textSize.Width) / 2,
                                        dy + (CellSize - textSize.Height) / 2);
                                    break;
                            }
                        } else if (!cellBlockRole.IsShowResult && cellBlockRole.IsFlag) //未翻开的红色旗子区域
                        {
                            graphics.DrawImage(Image.FromHbitmap(Resources.flag.GetHbitmap()),
                                new RectangleF(dx, dy, CellSize, CellSize));
                        }
                    }
                }
            }
        }

        private void GameView_MouseDown(object sender, MouseEventArgs e)
        {
            int px = (e.X - 1) / (CellSize + 1),
                py = (e.Y - 1) / (CellSize + 1);
            CellBlockRole cellRole = gameMap[py][px];
            if (!cellRole.IsShowResult) //如果该坐标点的格子没有被翻起
            {
                switch (e.Button)
                {
                    case MouseButtons.Left: //鼠标左键
                        if (cellRole.IsFlag) return; //红旗标识的不能被点击
                        if (cellRole.IsBoom)
                        {
                            new Thread(() =>
                            {
                                ShowAllCellBlockRoleNumber();
                                InvalidateGameView(); //刷新游戏界面
                            }).Start();
                            gameTimer.Enabled = false;
                            OnGameOverEvent?.Invoke();
                        } else
                        {
                            new Thread(() =>
                            {
                                ShowNeiborhoodCellRolesByPosi(px, py);
                                InvalidateGameView(); //刷新游戏界面
                            }).Start();
                            OnShowANumberEvent?.Invoke();
                        }
                        break;
                    case MouseButtons.Right: //鼠标右键
                        gameMap[py][px].IsFlag = !cellRole.IsFlag;
                        Invalidate();
                        break;
                }
            }
        }

        /// <summary>
        /// 初始化游戏
        /// </summary>
        private void InitGame()
        {
            new Thread(() =>
            {
                InitGameMap();
                GenerateBooms(BoomCount);
                InvalidateGameView(); //刷新游戏界面
            }).Start();
        }

        /// <summary>
        /// 设置游戏定时器
        /// </summary>
        private void SetGameTimer()
        {
            gameTimer.Tick += (sender, args) =>
            {
                long diffSecond = (long)(DateTime.Now - gameStartTime).TotalSeconds;
                long hour = diffSecond / (60 * 60),
                     minute = (diffSecond - hour * 60 * 60) / 60,
                     second = diffSecond - hour * 60 * 60 - minute * 60;
                OnPublishGameTimeEvent?.Invoke((hour > 0 ? (hour > 9 ? hour.ToString() : "0" + hour) + ":" : "")
                                               + (minute > 9 ? minute.ToString() : "0" + minute) + ":" + (second > 9 ? second.ToString() : "0" + second));
            };
            gameTimer.Interval = 1000;
            gameTimer.Enabled = true;
        }

        /// <summary>
        /// 启动游戏定时器
        /// </summary>
        private void StartGameTimer()
        {
            gameStartTime = TimeZone.CurrentTimeZone.ToLocalTime(DateTime.Now);
            gameTimer.Start();
        }


        /// <summary>
        /// 初始化游戏地图
        /// </summary>
        private void InitGameMap()
        {
            for (int i = 0; i < GameCellCount; i++)
            {
                gameMap[i] = new CellBlockRole[GameCellCount];
                for (int j = 0; j < GameCellCount; j++)
                {
                    gameMap[i][j] = new CellBlockRole
                    {
                        X = j,
                        Y = i
                    };
                }
            }
            StartGameTimer(); //启动游戏定时器
        }
        
        /// <summary>
        /// 重置游戏地图
        /// </summary>
        public void ResetGameMap()
        {
            new Thread(() =>
            {
                for (int i = 0; i < GameCellCount; i++)
                {
                    for (int j = 0; j < GameCellCount; j++)
                    {
                        gameMap[i][j].X = j;
                        gameMap[i][j].Y = i;
                        gameMap[i][j].Number = 0;
                        gameMap[i][j].IsShowResult = false;
                        gameMap[i][j].IsComputeResult = false;
                        gameMap[i][j].IsHasShowComputed = false;
                        gameMap[i][j].IsFlag = false;

                    }
                }
                GenerateBooms(BoomCount); //生成一些雷
                InvalidateGameView();
            }).Start();
            StartGameTimer(); //启动游戏定时器
        }

        /// <summary>
        /// 随机生成一些地雷
        /// </summary>
        public void GenerateBooms(int boomCount)
        {
            for (int i = 0; i < boomCount; i++)
            {
                int boomNumberIndex = Random.Next(0, GameCellCount * GameCellCount - 1); //生成随机数的范围
                int boomX = boomNumberIndex % GameCellCount,
                    boomY = boomNumberIndex / GameCellCount;
                if (gameMap[boomY][boomX].Number != -1)
                    gameMap[boomY][boomX].Number = -1; //-1表示雷
                else // 已经存在雷了，所以要重新处理
                    i--;
            }
            MakeAllNumberComputeInCellRole(0, 0); //默认从坐标（0，0）开始
        }

        /// <summary>
        /// 显示所有的格子的信息
        /// </summary>
        private void ShowAllCellBlockRoleNumber()
        {
            for (int i = 0; i < GameCellCount; i++)
            {
                for (int j = 0; j < GameCellCount; j++)
                {
                    gameMap[i][j].IsShowResult = true;
                }
            }
        }

        /// <summary>
        /// 显示某点周边所有格子的数字
        /// </summary>
        /// <param name="posiX">X轴坐标</param>
        /// <param name="posiY">Y轴坐标</param>
        private void ShowNeiborhoodCellRolesByPosi(int posiX, int posiY)
        {
            gameMap[posiY][posiX].IsShowResult = true;
            gameMap[posiY][posiX].IsHasShowComputed = true;
            int boomCount = GetBoomCountInNeiborhood(posiX, posiY);
            if (boomCount == 0) //如果周围没有雷，则翻开所有8个方向的相关数字
            {
                for (int i = 0; i < MoveDirectionPoints.Length; i++)
                {
                    int[] itemPosi = MoveDirectionPoints[i];
                    int rx = posiX + itemPosi[0],
                        ry = posiY + itemPosi[1];
                    bool isNotOutIndexRange = rx >= 0 && rx < GameCellCount && ry >= 0 && ry < GameCellCount;
                    if (isNotOutIndexRange) //防止坐标溢出
                    {
                        if (!gameMap[ry][rx].IsFlag)
                            gameMap[ry][rx].IsShowResult = true;
                        if (!gameMap[ry][rx].IsFlag && !gameMap[ry][rx].IsHasShowComputed && gameMap[ry][rx].Number == 0)
                            ShowNeiborhoodCellRolesByPosi(rx, ry);
                    }
                }
            }
        }

        /// <summary>
        /// 获取某点附近的雷数量
        /// </summary>
        /// <param name="posiX">X轴坐标点</param>
        /// <param name="posiY">Y轴坐标点</param>
        /// <returns></returns>
        private int GetBoomCountInNeiborhood(int posiX, int posiY)
        {
            int boomCount = 0;
            for (int i = 0; i < MoveDirectionPoints.Length; i++)
            {
                int[] itemPosi = MoveDirectionPoints[i];
                int rx = posiX + itemPosi[0],
                    ry = posiY + itemPosi[1];
                bool isNotOutIndexRange = rx >= 0 && rx < GameCellCount && ry >= 0 && ry < GameCellCount;
                if (isNotOutIndexRange && gameMap[ry][rx].IsBoom) //防止坐标溢出
                {
                    boomCount++;
                }
            }
            return boomCount;
        }

        /// <summary>
        /// 计算每个格子的数字标识
        /// </summary>
        /// <param name="posiX">X轴坐标</param>
        /// <param name="posiY">Y轴坐标</param>
        private void MakeAllNumberComputeInCellRole(int posiX, int posiY)
        {
            int boomCount = GetBoomCountInNeiborhood(posiX, posiY);
            if (boomCount != 0) //如果周围没有雷，则计算周围的8个方向的格子
            {
                gameMap[posiY][posiX].Number = boomCount;
            } else
            {
                if (!gameMap[posiY][posiX].IsBoom)
                    gameMap[posiY][posiX].Number = 0;
            }
            gameMap[posiY][posiX].IsComputeResult = true;
            for (int i = 0; i < MoveDirectionPoints.Length; i++)
            {
                int[] itemPosi = MoveDirectionPoints[i];
                int rx = posiX + itemPosi[0],
                    ry = posiY + itemPosi[1];
                bool isNotOutIndexRange = rx >= 0 && rx < GameCellCount && ry >= 0 && ry < GameCellCount;
                if (isNotOutIndexRange && !gameMap[ry][rx].IsComputeResult && !gameMap[ry][rx].IsBoom) //防止坐标溢出
                {
                    MakeAllNumberComputeInCellRole(rx, ry);
                }
            }
        }


        /// <summary>
        /// 刷新游戏界面
        /// </summary>
        private void InvalidateGameView()
        {
            if (this.InvokeRequired)
            {
                MethodInvoker del = Invalidate;
                this.Invoke(del);
            } else
            {
                Invalidate();
            }
        }

    }

}
